package cn.simon.free.ratelimiter.config;

import cn.simon.free.ratelimiter.annotation.RateLimiter;
import cn.simon.free.ratelimiter.core.RateInit;
import cn.simon.free.ratelimiter.utils.IpUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;

/**
 * 限流过滤器
 *
 * @author simon
 * @date 2020/3/20 15:52
 * @copyright:
 * @modifier
 * @motto a no talent, people who have to study hard
 */
@Configuration
@ConditionalOnProperty(prefix = "rate-limit", name = "enable", havingValue = "true")
public class WebAppInterceptorConfig implements WebMvcConfigurer {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new RateLimiterInterceptor()).addPathPatterns("/**");
    }

    public class RateLimiterInterceptor extends HandlerInterceptorAdapter {

        private final Logger log = LoggerFactory.getLogger(RateLimiterInterceptor.class);

        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
            String ip = IpUtils.getIPAddress(request);
            log.info("remote ip : {}", ip);
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            RateLimiter annotation = handlerMethod.getMethod().getAnnotation(RateLimiter.class);
            if (Objects.isNull(annotation)) return true;
            return checkMethodRate(handlerMethod);
        }

        private boolean checkMethodRate(HandlerMethod handlerMethod) {
            String hashCode = String.valueOf(handlerMethod.getMethod().hashCode());
            return RateInit.getCacheProvider().checkAuthority(hashCode);
        }

        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        }

        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        }
    }
}
